/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
define(["require", "exports", "../utils/convert", "../utils/regexp"], function (require, exports, convert_1, regexp_1) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    class CodeLens {
        constructor(range, command) {
            this.range = range;
            this.command = command;
        }
        get isResolved() {
            return !!this.command;
        }
    }
    exports.CodeLens = CodeLens;
    class ReferencesCodeLens extends CodeLens {
        constructor(document, file, range) {
            super(range);
            this.document = document;
            this.file = file;
        }
    }
    exports.ReferencesCodeLens = ReferencesCodeLens;
    class CachedNavTreeResponse {
        constructor() {
            this.version = -1;
            this.document = '';
        }
        execute(document, f) {
            if (this.matches(document)) {
                return this.response;
            }
            return this.update(document, f());
        }
        matches(document) {
            return this.version === document.version && this.document === document.uri.toString();
        }
        update(document, response) {
            this.response = response;
            this.version = document.version;
            this.document = document.uri.toString();
            return response;
        }
    }
    exports.CachedNavTreeResponse = CachedNavTreeResponse;
    class TypeScriptBaseCodeLensProvider {
        constructor(client, cachedResponse, vscode) {
            this.client = client;
            this.cachedResponse = cachedResponse;
            this.vscode = vscode;
            this.enabled = true;
            this.onDidChangeCodeLensesEmitter = new this.vscode.EventEmitter();
        }
        get onDidChangeCodeLenses() {
            return this.onDidChangeCodeLensesEmitter.event;
        }
        setEnabled(enabled) {
            if (this.enabled !== enabled) {
                this.enabled = enabled;
                this.onDidChangeCodeLensesEmitter.fire();
            }
        }
        provideCodeLenses(document, token) {
            return __awaiter(this, void 0, void 0, function* () {
                if (!this.enabled) {
                    return [];
                }
                const filepath = this.client.normalizePath(document.uri);
                if (!filepath) {
                    return [];
                }
                try {
                    const response = yield this.cachedResponse.execute(document, () => this.client.execute('navtree', { file: filepath }, token));
                    if (!response) {
                        return [];
                    }
                    const tree = response.body;
                    const referenceableSpans = [];
                    if (tree && tree.childItems) {
                        tree.childItems.forEach((item) => this.walkNavTree(document, item, null, referenceableSpans));
                    }
                    return referenceableSpans.map(span => {
                        var codelens = new this.vscode.CodeLens(span);
                        codelens.document = document.uri;
                        codelens.file = filepath;
                        return codelens;
                    });
                }
                catch (_a) {
                    return [];
                }
            });
        }
        walkNavTree(document, item, parent, results) {
            if (!item) {
                return;
            }
            const range = this.extractSymbol(document, item, parent);
            if (range) {
                results.push(range);
            }
            (item.childItems || []).forEach((child) => this.walkNavTree(document, child, item, results));
        }
        /**
         * TODO: TS currently requires the position for 'references 'to be inside of the identifer
         * Massage the range to make sure this is the case
         */
        getSymbolRange(document, item) {
            if (!item) {
                return null;
            }
            const span = item.spans && item.spans[0];
            if (!span) {
                return null;
            }
            const range = convert_1.tsTextSpanToVsRange(span, this.vscode);
            const text = document.getText(range);
            const identifierMatch = new RegExp(`^(.*?(\\b|\\W))${regexp_1.escapeRegExp(item.text || '')}(\\b|\\W)`, 'gm');
            const match = identifierMatch.exec(text);
            const prefixLength = match ? match.index + match[1].length : 0;
            const startOffset = document.offsetAt(new this.vscode.Position(range.start.line, range.start.character)) + prefixLength;
            return new this.vscode.Range(document.positionAt(startOffset), document.positionAt(startOffset + item.text.length));
        }
    }
    exports.TypeScriptBaseCodeLensProvider = TypeScriptBaseCodeLensProvider;
});
